/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package model;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import util.DBWrapper;

/**
 * 
 * @author onfire
 */
public abstract class Model {

	private Connection conn;
	private boolean create = false;

	public Model() {
		this.conn = new DBWrapper().getConnection();
	}

	public boolean isCreate() {
		return create;
	}

	public void create() {
		this.create = true;
	}

	public ResultSet query(String sql) {
		Statement st = null;
		ResultSet rs = null;
		try {
			st = conn.createStatement();
			rs = st.executeQuery(sql);
			// st.close();
		} catch (SQLException ex) {
			Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
		}
		return rs;
	}

	public boolean queryUpdate(String sql) {
		Statement st = null;
		boolean success = false;
		try {
			st = conn.createStatement();
			success = st.execute(sql);
			st.close();
		} catch (SQLException ex) {
			Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
		}
		return success;
	}

	protected boolean remove(Model m) throws IllegalArgumentException,
			SecurityException, IllegalAccessException,
			InvocationTargetException, NoSuchMethodException {
		String tableName = m.getClass().getSimpleName().toLowerCase();
		return queryUpdate("DELETE FROM " + tableName + " WHERE id="
				+ m.getClass().getDeclaredMethod("getId").invoke(m));
	}

	public boolean remove() {
		try {
			return remove(this);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
		return false;
	}

	protected void load(Model m, int id) throws SQLException,
			IllegalArgumentException, SecurityException,
			IllegalAccessException, InvocationTargetException,
			NoSuchMethodException {

		Field[] fields = m.getClass().getDeclaredFields();
		String tableName = m.getClass().getSimpleName().toLowerCase();

		String sql = "SELECT * FROM " + tableName + " WHERE id=" + id;

		ResultSet rs = query(sql);

		if (rs.next()) {
			for (Field f : fields) {
				// if (!f.getName().equals("id")) {
				String fieldName = f.getName().substring(0, 1).toUpperCase()
						+ f.getName().substring(1, f.getName().length());
				// String fieldSetMethod = "set" + fieldName;

				// System.out.println(f.getType());

				f.set(m, rs.getObject(fieldName));

				// m.getClass().getDeclaredMethod(fieldSetMethod,
				// f.getType())
				// .invoke(m, f.getType().cast(rs.getObject(f.getName())));
				// }
			}
		}

	}

	public void load(int id) {
		try {
			load(this, id);
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
	}

	protected boolean save(Model m) throws IllegalArgumentException,
			IllegalAccessException, InstantiationException,
			ClassNotFoundException, SecurityException,
			InvocationTargetException, NoSuchMethodException {
		boolean success = false;
		Field[] fields = m.getClass().getDeclaredFields();
		String tableName = m.getClass().getSimpleName().toLowerCase();
		if (this.isCreate()) {
			String sql = "INSERT INTO " + tableName + "(";
			String sqlFields = "";
			String questionMasks = "";

			for (Field f : fields) {
				sqlFields += f.getName() + ",";
				questionMasks += "?,";
			}
			sqlFields = sqlFields.substring(0, sqlFields.length() - 1);
			questionMasks = questionMasks.substring(0,
					questionMasks.length() - 1);
			sql += sqlFields + ") VALUES (" + questionMasks + ")";

			try {
				PreparedStatement ps = conn.prepareStatement(sql);
				int i = 0;
				for (Field f : fields) {
					i++;
					String fieldName = f.getName().substring(0, 1)
							.toUpperCase()
							+ f.getName().substring(1, f.getName().length());
					String fieldGetMethod = "get" + fieldName;

					Object value = null;
					value = m.getClass().getDeclaredMethod(fieldGetMethod)
							.invoke(m);
					ps.setObject(i, value);
				}
				return ps.execute();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} else {
			String sql = "UPDATE " + tableName + " SET ";
			String sqlFields = "";

			for (Field f : fields) {
				if (!f.getName().equals("id"))
					sqlFields += f.getName() + "=?,";
			}
			sqlFields = sqlFields.substring(0, sqlFields.length() - 1);
			sql += sqlFields + " WHERE id="
					+ m.getClass().getDeclaredMethod("getId").invoke(m);

			try {
				PreparedStatement ps = conn.prepareStatement(sql);
				int i = 0;
				for (Field f : fields) {
					if (!f.getName().equals("id")) {
						i++;
						String fieldName = f.getName().substring(0, 1)
								.toUpperCase()
								+ f.getName()
										.substring(1, f.getName().length());
						String fieldGetMethod = "get" + fieldName;

						Object value = null;
						value = m.getClass().getDeclaredMethod(fieldGetMethod)
								.invoke(m);
						ps.setObject(i, value);
					}
				}
				return ps.execute();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		}
		return success;
	}

	public boolean save() {
		try {
			return save(this);
		} catch (IllegalArgumentException ex) {
			Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
		} catch (IllegalAccessException ex) {
			Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
		} catch (InstantiationException ex) {
			Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
		} catch (ClassNotFoundException ex) {
			Logger.getLogger(Model.class.getName()).log(Level.SEVERE, null, ex);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
		return false;
	}
}
